home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 1.iso / toolbox / src / exampleCode / opengl / debugHelper / README < prev   
Text File  |  1996-11-11  |  5KB  |  132 lines

  1.  
  2.          ~4Dgifts/toolbox/src/exampleCode/opengl/debugHelper README
  3.  
  4.  
  5.    override DSO functions to trace a program's OpenGL calls w/out recompiling
  6.  
  7.  
  8.       NOTE:  this has nothing whatsoever to do with the actual OpenGL
  9.          Debug application being implemented by the OpenGL group.
  10.          it is included here in the D.T. as a practical utility
  11.          until the real thing comes along.
  12.         
  13.  
  14.  
  15.     This is an "OpenGLDebug" used by the Inventor group when developing
  16.     Open Inventor.  It helped find lots of bugs in both Open Inventor and
  17.     OpenGL.  It prints out a trace of the OpenGL calls made by the program
  18.     as it runs.
  19.     
  20.     It does not intercept all OpenGL calls, only the subset of OpenGL (and
  21.     GLU and GLX) calls made by Open Inventor.  However, it is easy to add
  22.     routines that are missing.
  23.     
  24.     The technique used to intercept the OpenGL calls made by any
  25.     application, call a different routine, and then have that routine call
  26.     the real OpenGL routine, is very powerful.  Using this technique, you
  27.     can override any public routine in any DSO, for any non-setuid
  28.     program.  The possibilities for Deep Hacks are endless.
  29.  
  30.  
  31.     
  32.     Using This as an stand-in OpenGLDebug pretender:
  33.     ------------------------------------------------
  34.     First, you must compile OpenGL.c into a DSO:
  35.     
  36. cc -O -c OpenGL.c
  37. ld -shared OpenGL.o -o libGL.so
  38.     
  39.     Next, you must tell the run-time linker to look for DSO's in the
  40.     current directory before /usr/lib:
  41.     
  42. LD_LIBRARY_PATH=. ; export LD_LIBRARY_PATH  # If using sh/ksh
  43. setenv LD_LIBRARY_PATH .                    # If using csh/tcsh
  44.     
  45.     Then, run any OpenGL program.  As an example:
  46.     
  47. ivview -pq ../../inventor/inventorTemplates/models/queen.iv
  48.     
  49.     (NOTE:  ivview hails from the "inventor_eoe.sw.inventor" subsystem)
  50.  
  51.  
  52.     By default, OpenGL.c produces lines that look like:
  53.     OPENGL:     glEnable(GL_LIGHT0);
  54.  
  55.     If the GLCODE environment variable is set to anything, then the
  56.     OPENGL: prefix is removed, producing compilable code (for most calls;
  57.     some calls don't produce compilable code).  OpenGL.c will do a 
  58.     reasonable job of producing compilable code if you set the GLCODE 
  59.     environment variable.
  60.  
  61.     Also note that some OpenGL routines call other OpenGL routines to do
  62.     their work (e.g.  glXChooseVisual calls glXGetConfig); these are
  63.     tagged by their recursion level instead of 'OPENGL' when printed.
  64.  
  65.     
  66.     How It Works
  67.     ------------
  68.     First, we write a routine with the same arguments and result as the
  69.     real GL routine:
  70.     
  71.     GLuint
  72.     glGenLists(GLsizei range)
  73.     {
  74.         ... print out debug info ...
  75.     
  76.         return /* ??? return something ??? */;
  77.     }
  78.     
  79.     In OpenGL.c, the print stuff gets pretty fancy-- gl_header() keeps
  80.     track of indentation, gl_lookup_enum() translates from enumerated
  81.     constants to a human-readable string, etc.  But that is all pretty
  82.     straightforward.
  83.     
  84.     The tricky part is actually arranging to call the real glGenLists()
  85.     routine.  We obviously can't just call it directly, because the
  86.     compiler would interpret that as a recursive call to our replacement
  87.     glGenLists() routine.
  88.     
  89.     Instead, we use the dlopen() and dlsym() routines.  dlopen() allows
  90.     us to explicitly open up /usr/lib/libGL.so, the real OpenGL DSO.  Then
  91.     dlsym() lets us find the real routines in the real DSO, and returns a
  92.     pointer to the real routine.  We can then call the real routine
  93.     through that pointer, passing in any arguments and noting any result.
  94.     Written out for glGenLists(), it would look something like:
  95.     
  96.     void
  97.     glGenLists(GLenum mode)
  98.     {
  99.         int result;
  100.     
  101.         printf("glGenLists(%d)\n", mode);
  102.     
  103.         void *glDSO = dlopen("/usr/lib/libGL.so", RTLD_LAZY);
  104.         /* check for error... */
  105.         void (*real_glGenLists)(GLenum) = dlsym(glDSO, "glGenLists");    
  106.         /* check for error... */
  107.     
  108.         result = (*real_glGenLists)(mode);
  109.     
  110.         dlclose(glDSO);
  111.     
  112.         return result;
  113.     }
  114.     
  115.     Because the code for all the GL routines would look very, very
  116.     similar, and because it would be really slow to call
  117.     dlopen()/dlsym()/dlclose() for every GL routine, this DSO magic is
  118.     packaged up into some handy macros that all the routines call.  The
  119.     macros arrange to:
  120.       -- only dlopen() libGL.so once
  121.       -- only lookup a routine using dlsym() once
  122.     
  123.     Most of the code at the top of OpenGL.c could be adapted for any other
  124.     DSO in the system; just write appropriate versions of GL_GETSYM,
  125.     GL_CALL and GL_RCALL that lookup symbols in another DSO.
  126.     
  127.     Writing a preprocessor that reads a .h file and automatically
  128.     generates 'interception' code is left as an exercise for the reader,
  129.     as is writing code that actively trys to find OpenGL errors (e.g.
  130.     passing NaN or Infinity as arguments, calling glPopMatrix too many
  131.     times, etc).
  132.